package com.uzai.console.service.tencent.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.PicOperations;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.faceid.v20180301.FaceidClient;
import com.tencentcloudapi.faceid.v20180301.models.PhoneVerificationRequest;
import com.tencentcloudapi.faceid.v20180301.models.PhoneVerificationResponse;
import com.uzai.common.enums.*;
import com.uzai.common.exception.BusinessException;
import com.uzai.common.result.ResponseCode;
import com.uzai.console.common.utils.CommonUtil;
import com.uzai.console.common.utils.DateUtil;
import com.uzai.console.common.utils.Tools;
import com.uzai.console.config.UzaiConsoleSysConfig;
import com.uzai.console.dto.tencent.TencentCosConfigDto;
import com.uzai.console.entity.MerBaseConfig;
import com.uzai.console.enums.TensentCosErrorEnum;
import com.uzai.console.mapper.MerBaseConfigMapper;
import com.uzai.console.service.tencent.TencentCosService;
import com.uzai.console.vo.base.SelectKeyVo;
import com.uzai.console.vo.tencent.TencentCosConfigInfoVo;
import com.uzai.console.vo.tencent.TencentCosConfig;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author jianghan
 * @date 2019-06-18 15:06
 */
@Service
public class TencentCosServiceImpl implements TencentCosService {
    private static Logger logger = LoggerFactory.getLogger(TencentCosServiceImpl.class);

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MerBaseConfigMapper merBaseConfigMapper;
    @Autowired
    private UzaiConsoleSysConfig uzaiConsoleSysConfig;

    /**
     * 上传
     * @author lucher
     * @date 2022/3/9 15:40
     * @param merId
     * @param inputStream
     * @param fileName
     * @return java.lang.String
     */
    @Override
    public String upload(Long merId, InputStream inputStream, String fileName) {
        String fileUrl = "";
        //先获取参数配置
        TencentCosConfig tencentCosConfigVo = getTencentCosConfigByMerId(merId);
        if(tencentCosConfigVo == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请保存腾讯云配置");
        }

        //存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = tencentCosConfigVo.getBucketName();
        COSClient cosClient = null;

        try {

//            // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
//            // 详细代码参见本页：高级接口 -> 创建 TransferManager
//            TransferManager transferManager = createTransferManager(tencentCosConfigVo);
//
//            ObjectMetadata objectMetadata = new ObjectMetadata();
//            // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
//            // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
//            objectMetadata.setContentLength(inputStream.available());
//            //objectMetadata.setContentType(contentType);
//            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata);
//
//            // 高级接口会返回一个异步结果Upload
//            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回UploadResult, 失败抛出异常
//            Upload upload = transferManager.upload(putObjectRequest);
//            UploadResult uploadResult = upload.waitForUploadResult();
//            if(uploadResult != null){
//                String key =  uploadResult.getKey();
//                TencentCosRegionEnum tencentCosRegionEnum = TencentCosRegionEnum.getValue(tencentCosConfigVo.getRegion());
//                if(tencentCosRegionEnum != null){
//                    fileUrl = "https://" + tencentCosRegionEnum.getDomain().replace("<BucketName>", tencentCosConfigVo.getBucketName()) + "/" + key;
//                }
//            }

            //创建低端上传文件
            cosClient = createCOSClient(tencentCosConfigVo);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
            // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
            objectMetadata.setContentLength(inputStream.available());
            //objectMetadata.setContentType(contentType);
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata);

            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            if(putObjectResult != null ) {
                TencentCosRegionEnum tencentCosRegionEnum = TencentCosRegionEnum.getValue(tencentCosConfigVo.getRegion());
                if (tencentCosRegionEnum != null) {
                    if(StringUtils.isBlank(tencentCosConfigVo.getDomain())){
                        fileUrl = "https://" + tencentCosRegionEnum.getDomain().replace("<BucketName>", tencentCosConfigVo.getBucketName()) + "/" + fileName;
                    }else{
                        fileUrl = tencentCosConfigVo.getDomain() + "/" + fileName;
                    }

                }
            }
        } catch (CosClientException cosClientException){
            logger.error("上传腾讯云文件失败：errorCode={}" , cosClientException.getErrorCode());
            TensentCosErrorEnum tensentCosErrorEnum = TensentCosErrorEnum.getByMessage(cosClientException.getErrorCode());
            String returnMessage = "上传失败";
            if(tensentCosErrorEnum != null){
                returnMessage = tensentCosErrorEnum.getDesc();
            }
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, returnMessage);
        } catch (Exception e) {
            logger.error("上传文件失败：error={}" +e.getMessage());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "上传失败");
        }finally{
            // 确定本进程不再使用 transferManager 实例之后，关闭之
            // 详细代码参见本页：高级接口 -> 关闭 TransferManager
            //shutdownTransferManager(transferManager);
            //关闭低端接口
            if(cosClient != null){
                cosClient.shutdown();
            }
        }

        return fileUrl;
    }

    /**
     * 上传并转图片格式
     * @author lucher
     * @date 2022/3/9 15:40
     * @param merId
     * @param inputStream
     * @param fileName
     * @param format 转化成的图片格式
     * @return java.lang.String
     */
    @Override
    public String uploadAndTrans(Long merId, InputStream inputStream, String fileName, String format) {
        String fileUrl = "";
        //先获取参数配置
        TencentCosConfig tencentCosConfigVo = getTencentCosConfigByMerId(merId);
        if(tencentCosConfigVo == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请保存腾讯云配置");
        }

        //存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = tencentCosConfigVo.getBucketName();
        COSClient cosClient = null;

        try {

//            // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
//            // 详细代码参见本页：高级接口 -> 创建 TransferManager
//            TransferManager transferManager = createTransferManager(tencentCosConfigVo);
//
//            ObjectMetadata objectMetadata = new ObjectMetadata();
//            // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
//            // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
//            objectMetadata.setContentLength(inputStream.available());
//            //objectMetadata.setContentType(contentType);
//            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata);
//
//            // 高级接口会返回一个异步结果Upload
//            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回UploadResult, 失败抛出异常
//            Upload upload = transferManager.upload(putObjectRequest);
//            UploadResult uploadResult = upload.waitForUploadResult();
//            if(uploadResult != null){
//                String key =  uploadResult.getKey();
//                TencentCosRegionEnum tencentCosRegionEnum = TencentCosRegionEnum.getValue(tencentCosConfigVo.getRegion());
//                if(tencentCosRegionEnum != null){
//                    fileUrl = "https://" + tencentCosRegionEnum.getDomain().replace("<BucketName>", tencentCosConfigVo.getBucketName()) + "/" + key;
//                }
//            }

            //创建低端上传文件
            cosClient = createCOSClient(tencentCosConfigVo);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
            // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
            objectMetadata.setContentLength(inputStream.available());
            //objectMetadata.setContentType(contentType);
            //图片转换格式参数
            PicOperations picOperations = new PicOperations();
            picOperations.setIsPicInfo(1); //返回原图信息
            List<PicOperations.Rule> rules = new ArrayList<>();
            PicOperations.Rule rule = new PicOperations.Rule();
            String[] fileNameArr = fileName.split("\\.");
            String transFileName = fileNameArr[0]+"."+format;
            rule.setBucket(tencentCosConfigVo.getBucketName());
            rule.setFileId(transFileName);
            rule.setRule("imageMogr2/format/"+format);
            rules.add(rule);
            picOperations.setRules(rules);
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata);
            putObjectRequest.setPicOperations(picOperations);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            if(putObjectResult != null ) {
                TencentCosRegionEnum tencentCosRegionEnum = TencentCosRegionEnum.getValue(tencentCosConfigVo.getRegion());
                if (tencentCosRegionEnum != null) {
                    fileUrl = "https://" + tencentCosRegionEnum.getDomain().replace("<BucketName>", tencentCosConfigVo.getBucketName()) + "/" + transFileName;
                }
            }
        } catch (CosClientException cosClientException){
            logger.error("上传腾讯云文件失败：errorCode={}" , cosClientException.getErrorCode());
            TensentCosErrorEnum tensentCosErrorEnum = TensentCosErrorEnum.getByMessage(cosClientException.getErrorCode());
            String returnMessage = "上传失败";
            if(tensentCosErrorEnum != null){
                returnMessage = tensentCosErrorEnum.getDesc();
            }
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, returnMessage);
        } catch (Exception e) {
            logger.error("上传文件失败：error={}" +e.getMessage());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "上传失败");
        }finally{
            // 确定本进程不再使用 transferManager 实例之后，关闭之
            // 详细代码参见本页：高级接口 -> 关闭 TransferManager
            //shutdownTransferManager(transferManager);
            //关闭低端接口
            if(cosClient != null){
                cosClient.shutdown();
            }
        }

        return fileUrl;
    }



    /**
     *
     * @author lucher
     * @date 2022/3/9 15:37
     * @param merId
     * @return com.uzai.console.entity.TencentCosConfig
     */
    @Override
    public TencentCosConfig getTencentCosConfigByMerId(Long merId) {
        String tencentCosConfigStr = (String) redisTemplate.opsForValue().get(String.format(RedisCacheKeyEnum.TENCENT_COS_CONFIG.getKey(), merId));
        if(StringUtils.isNotBlank(tencentCosConfigStr)){
            TencentCosConfig tencentCosConfig = JSONObject.parseObject(tencentCosConfigStr, TencentCosConfig.class);
            return tencentCosConfig;
        }else{
            //从数据库当中查询
            MerBaseConfig merBaseConfig = merBaseConfigMapper.selectByMerId(merId, MerConfigKeyEnum.TENCENT_COS_CONFIG.getValue());
            if(merBaseConfig != null && StringUtils.isNotBlank(merBaseConfig.getVal())){
                TencentCosConfig tencentCosConfig = JSONObject.parseObject(merBaseConfig.getVal(), TencentCosConfig.class);
                return tencentCosConfig;
            }else { //数据库当中也没有
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请先配置腾讯云对象储存");
            }
        }
    }

    /**
     * 验证腾讯云对象存储配置信息是否正确
     * @author jitwxs
     * @date 2022/1/18 14:25
     * @param tencentCosConfigDto
     */
    public Boolean checkConfig(TencentCosConfigDto tencentCosConfigDto){

        Boolean checkFlag = false;

        String appId = Tools.getStr(tencentCosConfigDto.getAppId());
        if(StringUtils.isBlank(appId)){
            throw new BusinessException(ResponseCode.PARAMETER_EXCEPTION, "appId不能为空");
        }
        String secretId = Tools.getStr(tencentCosConfigDto.getSecretId());
        if(StringUtils.isBlank(secretId)){
            throw new BusinessException(ResponseCode.PARAMETER_EXCEPTION, "密钥id不能为空");
        }
        String secretKey = Tools.getStr(tencentCosConfigDto.getSecretKey());
        if(StringUtils.isBlank(secretKey)){
            throw new BusinessException(ResponseCode.PARAMETER_EXCEPTION, "密钥SK不能为空");
        }
        String bucketName = Tools.getStr(tencentCosConfigDto.getBucketName());
        if(StringUtils.isBlank(bucketName)){
            throw new BusinessException(ResponseCode.PARAMETER_EXCEPTION, "存储桶名称不能为空");
        }
        String regionStr = tencentCosConfigDto.getRegion();
        if(StringUtils.isBlank(regionStr)){
            throw new BusinessException(ResponseCode.PARAMETER_EXCEPTION, "地域不能为空");
        }

        try{

            TencentCosConfig tencentCosConfigVo = new TencentCosConfig();
            BeanUtils.copyProperties(tencentCosConfigDto, tencentCosConfigVo);

            //1 初始化用户身份信息（secretId, secretKey）。
            COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
            // 2 设置 bucket 的地域
            Region region = new Region(regionStr);
            ClientConfig clientConfig = new ClientConfig(region);
            // 从 5.6.54 版本开始，默认使用了 https
            clientConfig.setHttpProtocol(HttpProtocol.https);
            // 3 生成 cos 客户端。
            COSClient cosClient = new COSClient(cred, clientConfig);
            checkFlag = cosClient.doesBucketExist(bucketName);
        }catch (Exception e){
            logger.error("--is error;  error={}",e.getMessage());
        }
        return checkFlag;
    }

    /**
     * 保存腾讯云对象存储云配置信息
     * @author jitwxs
     * @date 2022/1/18 14:25
     * @param tencentCosConfigDto
     */
    @Transactional
    public void addTencentCosConfig(TencentCosConfigDto tencentCosConfigDto){
        Boolean checkFlag = checkConfig(tencentCosConfigDto);
        Integer now = DateUtil.getNowTime();
        if(checkFlag){//验证成功，才能保存
            TencentCosConfig tencentCosConfigVo = new TencentCosConfig();
            BeanUtils.copyProperties(tencentCosConfigDto, tencentCosConfigVo);
            MerBaseConfig merBaseConfig = merBaseConfigMapper.selectByMerId(tencentCosConfigDto.getMerId(), MerConfigKeyEnum.TENCENT_COS_CONFIG.getValue());
            if(merBaseConfig != null){ //修改
                merBaseConfig.setVal(Tools.getStrEmpty(JSONObject.toJSONString(tencentCosConfigVo)));
                merBaseConfig.setUpdateTime(now);
                merBaseConfigMapper.update(merBaseConfig);
            }else{//新增
                merBaseConfig = new MerBaseConfig();
                merBaseConfig.setId(IdWorker.getId());
                merBaseConfig.setMerId(tencentCosConfigDto.getMerId());
                merBaseConfig.setType(MerConfigTypeEnum.PRODUCTS.getValue());
                merBaseConfig.setKey(MerConfigKeyEnum.TENCENT_COS_CONFIG.getValue());
                merBaseConfig.setVal(Tools.getStrEmpty(JSONObject.toJSONString(tencentCosConfigVo)));
                merBaseConfig.setCreateTime(now);
                merBaseConfig.setUpdateTime(now);
                merBaseConfigMapper.insert(merBaseConfig);
            }
            //保存到redis缓存中
            redisTemplate.opsForValue().set(String.format(RedisCacheKeyEnum.TENCENT_COS_CONFIG.getKey(), tencentCosConfigDto.getMerId()), Tools.getStrEmpty(JSONObject.toJSONString(tencentCosConfigVo)));

            //是否默认
            Integer isDefault =  Tools.getInteger(tencentCosConfigDto.getIsDefault());
            //文件存储类型
            MerBaseConfig merBaseConfig_fileSaveType = merBaseConfigMapper.selectByMerId(tencentCosConfigDto.getMerId(), MerConfigKeyEnum.FILE_SAVE_TYPE.getValue());
            if(merBaseConfig_fileSaveType != null){ //存在，则修改
                if(isDefault.intValue() == 1){ //默认启用腾讯云
                    merBaseConfig_fileSaveType.setVal(String.valueOf(FileSaveTypeEnum.TENCENT.getId()));
                    merBaseConfig_fileSaveType.setUpdateTime(now);
                    merBaseConfigMapper.update(merBaseConfig_fileSaveType);
                }else{ //不启用,判断旧启用是否采用腾讯云，如果是，则修改成未配置，如果不是，则不操作
                    if(Tools.getStr(merBaseConfig_fileSaveType.getVal()).equals(String.valueOf(FileSaveTypeEnum.TENCENT.getId()))){
                        merBaseConfig_fileSaveType.setVal(String.valueOf(FileSaveTypeEnum.NOCONFIG.getId()));
                        merBaseConfig_fileSaveType.setUpdateTime(now);
                        merBaseConfigMapper.update(merBaseConfig_fileSaveType);
                    }
                }
            }else{//新增
                merBaseConfig_fileSaveType = new MerBaseConfig();
                merBaseConfig_fileSaveType.setId(IdWorker.getId());
                merBaseConfig_fileSaveType.setMerId(tencentCosConfigDto.getMerId());
                merBaseConfig_fileSaveType.setType(MerConfigTypeEnum.PRODUCTS.getValue());
                merBaseConfig_fileSaveType.setKey(MerConfigKeyEnum.FILE_SAVE_TYPE.getValue());
                if(isDefault.intValue() == 1){ //启用
                    merBaseConfig_fileSaveType.setVal(String.valueOf(FileSaveTypeEnum.TENCENT.getId()));
                }else{
                    merBaseConfig_fileSaveType.setVal(String.valueOf(FileSaveTypeEnum.NOCONFIG.getId()));
                }
                merBaseConfig_fileSaveType.setCreateTime(now);
                merBaseConfig_fileSaveType.setUpdateTime(now);
                merBaseConfigMapper.insert(merBaseConfig_fileSaveType);
            }

            //保存到redis缓存中
            redisTemplate.opsForValue().set(String.format(RedisCacheKeyEnum.FILE_SAVE_TYPE.getKey(), tencentCosConfigDto.getMerId()), merBaseConfig_fileSaveType.getVal());

        }else{
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "配置错误");
        }
    }

    /**
     * 上传文件
     * @author liuqi
     * @date 2022/1/18 15:17
     * @return com.uzai.console.vo.tencentCosConfig.TencentCosConfigConfigUploadFileVo
     */
    public String uploadFile(MultipartFile multipartFile, Long merId){

        if(multipartFile == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请选择文件");
        }

        String fileUrl = "";
        String filename = multipartFile.getOriginalFilename();
        filename = CommonUtil.getUUID() + filename.substring(filename.lastIndexOf("."));

        String contentType = multipartFile.getContentType();

        try {
            fileUrl = upload(merId, multipartFile.getInputStream(), filename);
        } catch (Exception e) {
            logger.error("--is error; error={}", e.getMessage());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, e.getMessage());
        }
        return fileUrl;
    }

    /**
     * 上传文件并转化图片格式
     * @author liuqi
     * @date 2022/1/18 15:17
     * @return com.uzai.console.vo.tencentCosConfig.TencentCosConfigConfigUploadFileVo
     */
    public String uploadFileAndTrans(MultipartFile multipartFile, Long merId, String format){

        if(multipartFile == null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "请选择文件");
        }

        String fileUrl = "";
        String filename = multipartFile.getOriginalFilename();
        filename = CommonUtil.getUUID() + filename.substring(filename.lastIndexOf("."));

        String contentType = multipartFile.getContentType();

        try {
            fileUrl = uploadAndTrans(merId, multipartFile.getInputStream(), filename, format);
        } catch (Exception e) {
            logger.error("--is error; error={}", e.getMessage());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, e.getMessage());
        }
        return fileUrl;
    }



    /**
     * 查询腾讯云对象存储云详情
     * @author jitwxs
     * @date 2022/1/18 17:25
     * @param merId
     * @return com.uzai.console.vo.tencentCosConfig.TencentCosConfigConfigVo
     */
    public TencentCosConfigInfoVo findTencentCosConfigInfo(Long merId){
        TencentCosConfigInfoVo tencentCosConfigInfoVo = new TencentCosConfigInfoVo();
        MerBaseConfig merBaseConfig = merBaseConfigMapper.selectByMerId(merId, MerConfigKeyEnum.TENCENT_COS_CONFIG.getValue());
        //配置信息
        if(merBaseConfig != null){
            TencentCosConfig tencentCosConfig = JSONObject.parseObject(merBaseConfig.getVal(), TencentCosConfig.class);
            if(tencentCosConfig != null){
                BeanUtils.copyProperties(tencentCosConfig, tencentCosConfigInfoVo);
            }
        }

        //是否默认存储
        tencentCosConfigInfoVo.setIsDefault(0); //默认未启用
        MerBaseConfig merBaseConfig_fileSaveType = merBaseConfigMapper.selectByMerId(merId, MerConfigKeyEnum.FILE_SAVE_TYPE.getValue());
        if(merBaseConfig_fileSaveType != null){
            if(String.valueOf(FileSaveTypeEnum.TENCENT.getId()).equals(merBaseConfig_fileSaveType.getVal())){ //启用腾讯
                tencentCosConfigInfoVo.setIsDefault(1);
            }
        }
        return  tencentCosConfigInfoVo;
    }


    // 创建 TransferManager 实例，这个实例用来后续调用高级接口
    public TransferManager createTransferManager(TencentCosConfig tencentCosConfigVo) {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient(tencentCosConfigVo);

        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);

        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);

        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5*1024*1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1*1024*1024);
        transferManager.setConfiguration(transferManagerConfiguration);

        return transferManager;
    }

    // 创建 COSClient 实例，这个实例用来后续调用请求
    public COSClient createCOSClient(TencentCosConfig tencentCosConfigVo) {

        //1 初始化用户身份信息（secretId, secretKey）。
        COSCredentials cred = new BasicCOSCredentials(tencentCosConfigVo.getSecretId(), tencentCosConfigVo.getSecretKey());
        // 2 设置 bucket 的地域
        Region region = new Region(tencentCosConfigVo.getRegion());
        ClientConfig clientConfig = new ClientConfig(region);
        // 从 5.6.54 版本开始，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);

        // 以下的设置，是可选的：

        // 设置 socket 读取超时，默认 30s
        //clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时，默认 30s
        //clientConfig.setConnectionTimeout(30*1000);

        // 如果需要的话，设置 http 代理，ip 以及 port
        //clientConfig.setHttpProxyIp("httpProxyIp");
        //clientConfig.setHttpProxyPort(80);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }


    public void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(true);
    }

    public List<SelectKeyVo> findRegionList(){
        List<SelectKeyVo> selectKeyVoList = new ArrayList<>();
        TencentCosRegionEnum[] tencentCosRegionEnums = TencentCosRegionEnum.values();
        if(tencentCosRegionEnums != null){
            for (TencentCosRegionEnum tencentCosRegionEnum : tencentCosRegionEnums) {
                SelectKeyVo selectKeyVo = new SelectKeyVo();
                selectKeyVo.setKey(tencentCosRegionEnum.getValue());
                selectKeyVo.setValue(tencentCosRegionEnum.getDesc());
                selectKeyVoList.add(selectKeyVo);
            }
        }
        return selectKeyVoList;
    }

    /**
     * 手机号信息检验（三要素）
     * @author lucher
     * @date 2022/3/9 15:40
     * @param phone
     * @param name
     * @param idCard
     * @return java.lang.String
     */
    public Boolean authentication(String phone, String name, String idCard){

        boolean result = false;

        // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
        // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
        // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
        Credential cred = new Credential(uzaiConsoleSysConfig.getTencentRealNameVerificationSecretId(), uzaiConsoleSysConfig.getTencentRealNameVerificationSecretKey());
        // 实例化一个http选项，可选的，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("faceid.tencentcloudapi.com");
        // 实例化一个client选项，可选的，没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        FaceidClient client = new FaceidClient(cred, "", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        PhoneVerificationRequest req = new PhoneVerificationRequest();
        req.setIdCard(idCard);
        req.setName(name);
        req.setPhone(phone);
        // 返回的resp是一个PhoneVerificationResponse的实例，与请求对象对应
        PhoneVerificationResponse resp = null;
        try {
            resp = client.PhoneVerification(req);
            // 输出json格式的字符串回包
            logger.info("实名认证返回结果：resp={}", PhoneVerificationResponse.toJsonString(resp));
            System.out.println(PhoneVerificationResponse.toJsonString(resp));
        }catch (Exception e){
            logger.error("实名验证调用接口失败,error={}",e.getMessage());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "实名验证调用接口失败");
        }

        if(resp != null && StringUtils.isNotBlank(resp.getResult())){
            if(resp.getResult().equals("0")){
                result = true;
            }else  if(resp.getResult().equals("-4")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "手机号、身份证、姓名信息不一致");
            }else if(resp.getResult().equals("-6")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "手机号码不合法");
            }else if(resp.getResult().equals("-7")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "身份证号码有误");
            }else if(resp.getResult().equals("-8")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "姓名校验不通过");
            }else if(resp.getResult().equals("-9")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "没有记录");
            }else if(resp.getResult().equals("-11")){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "验证中心服务繁忙");
            }
        }else{
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "实名验证失败");
        }

        return result;
    }

}